/*
 * Tranquil Java Integrated Development Environment
 *
 * The GNU General Public License Version 3
 *
 * Copyright (C) 2021 Autumn Lamonte
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * @author Autumn Lamonte [AutumnWalksTheLake@gmail.com] ⚧ Trans Liberation Now
 * @version 1
 */
package tjide.ui;

import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;

import gjexer.TAction;
import gjexer.TApplication;
import gjexer.TButton;
import gjexer.TComboBox;
import gjexer.TList;
import gjexer.TWindow;
import gjexer.bits.CellAttributes;
import static gjexer.TCommand.*;
import static gjexer.TKeypress.*;

import tjide.debugger.DebugThread;
import tjide.debugger.Scope;

/**
 * CallstackWindow is a permanent window that shows the call stack.
 */
public class CallstackWindow extends TWindow {

    /**
     * Translated strings.
     */
    private static ResourceBundle i18n = ResourceBundle.getBundle(CallstackWindow.class.getName());

    // ------------------------------------------------------------------------
    // Constants --------------------------------------------------------------
    // ------------------------------------------------------------------------

    // ------------------------------------------------------------------------
    // Variables --------------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
     * The list of threads.
     */
    private List<DebugThread> threads;

    /**
     * The selected call stack thread.
     */
    private TComboBox thread;

    /**
     * The call stack list of frames.
     */
    private TList callstack;

    // ------------------------------------------------------------------------
    // Constructors -----------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
     * Construct window.
     *
     * @param parent the main application
     */
    public CallstackWindow(final TApplication parent) {
        super(parent, i18n.getString("windowTitle"), 0, 1, 60, 20,
            CENTERED | NOZOOMBOX | HIDEONCLOSE);

        final int buttonOffset = 14;

        statusBar = newStatusBar(i18n.getString("statusBar"));
        statusBar.addShortcutKeypress(kbF1, cmHelp,
            i18n.getString("statusBarHelp"));
        statusBar.addShortcutKeypress(kbF10, cmMenu,
            i18n.getString("statusBarMenu"));

        // The thread selection.
        addLabel(i18n.getString("thread"), 2, 1,
            new TAction() {
                public void DO() {
                    CallstackWindow.this.activate(thread);
                }
            });
        thread = addComboBox(15, 1, 28, new ArrayList<String>(), -1, 7,
            new TAction() {
                public void DO() {
                    switchCallstackThread();
                }
            });

        // The callstack itself.
        addLabel(i18n.getString("callstack"), 2, 3,
            new TAction() {
                public void DO() {
                    CallstackWindow.this.activate(callstack);
                }
            });
        callstack = addList(new ArrayList<String>(), 2, 4,
            getWidth() - buttonOffset - 5, getHeight() - 7);

        // Buttons
        addButton(i18n.getString("okButton"), getWidth() - buttonOffset, 4,
            new TAction() {
                public void DO() {
                    // Note that we hide, not close: this is a single
                    // persistent window.
                    CallstackWindow.this.hide();
                }
            });

        TButton cancelButton = addButton(i18n.getString("cancelButton"),
            getWidth() - buttonOffset, 6,
            new TAction() {
                public void DO() {
                    // Note that we hide, not close: this is a single
                    // persistent window.
                    CallstackWindow.this.hide();
                }
            });

        // Save this for last: make the cancel button default action.
        activate(cancelButton);

        hide();
    }

    // ------------------------------------------------------------------------
    // Event handlers ---------------------------------------------------------
    // ------------------------------------------------------------------------

    // ------------------------------------------------------------------------
    // TWindow ----------------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
     * Retrieve the background color.
     *
     * @return the background color
     */
    @Override
    public final CellAttributes getBackground() {
        return getTheme().getColor("callstackWindow.background");
    }

    /**
     * Retrieve the border color.
     *
     * @return the border color
     */
    @Override
    public CellAttributes getBorder() {
        if (inWindowMove) {
            return getTheme().getColor("callstackWindow.windowMove");
        }
        return getTheme().getColor("callstackWindow.background");
    }

    /**
     * Retrieve the color used by the window movement/sizing controls.
     *
     * @return the color used by the zoom box, resize bar, and close box
     */
    @Override
    public CellAttributes getBorderControls() {
        return getTheme().getColor("callstackWindow.borderControls");
    }

    // ------------------------------------------------------------------------
    // CallstackWindow --------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
     * Update call stack to reflect the current debug execution location.
     */
    public void updateCallstack() {
        // Set callstack to the current scope.
        TranquilApplication app = (TranquilApplication) getApplication();
        Scope debugScope = app.getDebugScope();
        if (debugScope == null) {
            callstack.setList(new ArrayList<String>());
        } else {
            callstack.setList(debugScope.getAllCallstackStrings());
            threads = debugScope.getThreads();
            List<String> threadNames = new ArrayList<String>();
            for (DebugThread thread: threads) {
                threadNames.add(thread.getName());
            }
            thread.setList(threadNames);
            thread.setText(debugScope.getThread().getName());
        }
    }

    /**
     * Update call stack to the selected thread name.
     */
    public void switchCallstackThread() {
        // Set callstack to the current scope.
        TranquilApplication app = (TranquilApplication) getApplication();
        Scope debugScope = app.getDebugScope();
        if ((debugScope == null)
            || (threads == null)
            || (debugScope == null)
        ) {
            callstack.setList(new ArrayList<String>());
            return;
        }
        String name = thread.getText();
        for (DebugThread thread: threads) {
            if (thread.getName().equals(name)) {
                callstack.setList(debugScope.getAllCallstackStrings(thread));
                return;
            }
        }

        // Shouldn't be able to get here.
        callstack.setList(new ArrayList<String>());
    }

}
